/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package pv1682010.gui;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import java.util.concurrent.ExecutionException;
import java.util.logging.Level;
import javax.swing.SwingWorker;
import javax.swing.table.AbstractTableModel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import pv1682010.User;
import pv1682010.UserException;
import pv1682010.UserManager;

/**
 *
 * @author Isamaru
 */
public class UserTableModel extends AbstractTableModel {

    final private Logger log = LoggerFactory.getLogger(UserTableModel.class);
    final private UserManager um;

    public UserTableModel(UserManager um) {
	super();
	if (um == null) {
	    throw new IllegalArgumentException("um");
	}
	this.um = um;
	getUpdateSW().execute();
    }

    private List<User> users = new ArrayList<User>();
    private final ChangesTable changedTable = new ChangesTable();

    @Override
    public int getRowCount() {
        return users.size();
    }
 
    @Override
    public int getColumnCount() {
        return 3;
    }

    @Override
    public String getColumnName(int columnIndex) {
	switch (columnIndex) {
	    case 0:
		return "Uco";
	    case 1:
		return "Name";
	    case 2:
		return "Administrator";
	    default:
		throw new IllegalArgumentException("columnIndex");
	}
    }

    @Override
    public Object getValueAt(int rowIndex, int columnIndex) {
        User user = users.get(rowIndex);
        switch (columnIndex) {
            case 0:
                return user.getUco();
            case 1:
                return user.getName();
            case 2:
                return user.isAdministrator();
            default:
                throw new IllegalArgumentException("columnIndex");
        }
    }

@Override
public Class<?> getColumnClass(int columnIndex) {
    switch (columnIndex) {
        case 0:
            return Integer.class;
        case 1:
	    return String.class;
        case 2:
            return Boolean.class;
        default:
            throw new IllegalArgumentException("columnIndex");
    }
}

    @Override
    public boolean isCellEditable(int rowIndex, int columnIndex) {
	return false;
    }

    public UserManager getUm() {
	return um;
    }

    public List<User> getUsers() {
	return Collections.unmodifiableList(users);
    }

    public void setUsers(List<User> users) {
	this.users = users;
	changedTable.clear(users);
	fireTableDataChanged();
    }

    public void updateUser(int rowIndex, String name, Boolean isAdministrator) {
	User user = users.get(rowIndex);
	boolean changed = false;
	changed |= user.setName(name);
	changed |= user.setAdministrator(isAdministrator);
	if (changed) {
	    changedTable.change(user);
	    log.info("Table model updated for row {}", rowIndex);
	    fireTableRowsUpdated(rowIndex, rowIndex);	
	}

    }

    public int newUser(Integer uco, String name, Boolean isAdministrator) {
	User user = new User(uco, name, isAdministrator);
	if (changedTable.exists(user)) {
	    log.error("User already exists!");
	    throw new IllegalArgumentException("User already exists!");
	}
	users.add(user);
	int rowIndex = (users.size()-1);
	changedTable.add(user);
	fireTableRowsInserted(rowIndex, rowIndex);
	log.info("User added to table model at row {}", rowIndex);
	return rowIndex;
    }

    public void deleteUser(int rowIndex) {
	User user = users.remove(rowIndex);
	changedTable.delete(user);
	log.info("User deleted from table model at row {}", rowIndex);
	fireTableRowsDeleted(rowIndex, rowIndex);
    }

    public int getRowByUco(int uco) {
	for (int i = 0; i < users.size(); i++) {
	    if (users.get(i).getUco() == uco) {
		return i;
	    }
	}
	return -1;
    }

    private SwingWorker<List<User>, Void> getUpdateSW() {
	return new SwingWorker<List<User>, Void>(){

	    @Override
	    protected void done() {
		try {
		    setUsers(get());
		} catch (InterruptedException ex) {
		    log.error("Exception thrown! ", ex);
		} catch (ExecutionException ex) {
		    log.error("Exception thrown! ", ex);
		}
	    }

	    @Override
	    protected List<User> doInBackground() throws Exception {
		return getUm().getUsers();
	    }

	};
    }

    public boolean changed() {
	return changedTable.changed();
    }

    public void saveToDb(ProgressMonitor pm) {
	pm.progress(1);
	log.info("Saving to DB!");	
	int i = 1;
	List<User> list = changedTable.getChanged();
	List<User> list2 = changedTable.getDeleted();
	List<User> list3 = changedTable.getNew();
	int max = list.size() + list2.size() + list3.size();
	// CHANGE
	for (User user : list) {
	    try {
		um.updateUser(user);
		pm.progress(1 + (i++ * 99 / max));
	    } catch (UserException ex) {
		log.error("Error updating user!", ex);
	    }
	}
	
	// REMOVE
	for (User user : list2) {
	    try {
		um.deleteUser(user);
		pm.progress(1 + (i++ * 99 / max));
	    } catch (UserException ex) {
		log.error("Error removing user!", ex);
	    }
	}

	// NEW
	for (User user : list3) {
	    try {
		um.addUser(user, "blank");
		pm.progress(1 + (i++ * 99 / max));
	    } catch (UserException ex) {
		log.error("Error adding user!", ex);
	    }
	}
    }
    
}
